package dataStructures.cachedIndex;

import java.io.File;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.LinkedHashMap;

import org.apache.xerces.parsers.SAXParser;

import xml.RouteToIdsCachedIndexHandler;
import xml.XmlStatisticsHandler;

public class RouteToIdsCachedIndex {
	
	private class RouteInProgress
	{
		byte[] cache = new byte[500000];
		int cacheIndex = 0;
		long filePos = 0;
	}
	
	
	private LinkedHashMap<ArrayList<Integer>, RouteInProgress> _routesInProgress = new LinkedHashMap<ArrayList<Integer>, RouteInProgress>();
	private LinkedHashMap<ArrayList<Integer>, Long> _routeToRouteAddress = new LinkedHashMap<ArrayList<Integer>, Long>();
	private RandomAccessFile _raf = null;
	
	private LinkedHashMap<String,Integer> _labelsToIdMap = null;
	private LinkedHashMap<ArrayList<Integer>,Integer> _routeToIdMap = null;
	private LinkedHashMap<ArrayList<Integer>,Integer> _nodesOfRouteMap = null;
	
	
	private ArrayList<String> _labelsList = new ArrayList<String>();
	private ArrayList<ArrayList<Integer>> _routesList = new ArrayList<ArrayList<Integer>>();
	
	private void WriteIndexMetaData() throws Exception
	{
		//number of labels
		_raf.writeInt(_labelsToIdMap.size());
		
		//serialize labels
		for(String l : _labelsToIdMap.keySet())
		{
			_raf.writeUTF(l);
			_labelsList.add(l);
		}
	
		//number of routs
		_raf.writeInt(_routeToIdMap.size());
		
		//serialize routes
		for(ArrayList<Integer> route : _routeToIdMap.keySet())
		{
			_routesInProgress.put(route, new RouteInProgress());
			_routesList.add(route);
			
			_raf.writeInt(route.size());
			for(int lid : route)
			{
				_raf.writeInt(lid);
			}
		}

		for(ArrayList<Integer> route : _routesList)
		{
			int nodesOfRoute = _nodesOfRouteMap.get(route);
			//point to the block where all nodes saved (first 4 bytes are node's list's size)
			_routeToRouteAddress.put(route, _raf.getFilePointer());
			_raf.writeInt(nodesOfRoute);

			//point to the next address to write nodes to
			_routesInProgress.get(route).filePos = _raf.getFilePointer();
			_raf.seek(_raf.getFilePointer() + 4 * nodesOfRoute);
		}
	}
	
	public RouteToIdsCachedIndex(String xmlFile,String indexFile) throws Exception
	{
		new File(indexFile).delete();
		_raf = new RandomAccessFile(indexFile,"rws");
		SAXParser saxParser = new SAXParser();
		XmlStatisticsHandler statsHandler = new XmlStatisticsHandler();
		saxParser.setContentHandler(statsHandler);
		saxParser.parse(xmlFile);
		
		_labelsToIdMap =  statsHandler.GetLabels();
		_routeToIdMap = statsHandler.GetRouts();

		WriteIndexMetaData();
		
		
		RouteToIdsCachedIndexHandler handler = new RouteToIdsCachedIndexHandler(this);
		saxParser.setContentHandler(handler);
		saxParser.parse(xmlFile);
		
		for(ArrayList<Integer> r : _routesInProgress.keySet())
		{
			FlushRoute(_routesInProgress.get(r));
			_routesInProgress.get(r).cache = null;
		}
		
		System.gc();
		
		
		
	}
	
	public int GetlabelId(String label)
	{
		return _labelsToIdMap.get(label);
	}
	
	public RouteToIdsCachedIndex(String indexFile)
	{
		
	}
	
	private void FlushRoute(RouteInProgress r) throws Exception
	{
		_raf.seek(r.filePos);
		_raf.write(r.cache, 0, r.cacheIndex);
		r.filePos = _raf.getFilePointer();
	}
	public void AddNodeToRoute(int nodeId,ArrayList<Integer> route) throws Exception
	{
		RouteInProgress r = _routesInProgress.get(route);
		if (r.cacheIndex == 500000)
		{
			FlushRoute(r);
		}
		r.cache[r.cacheIndex++] = (byte)(nodeId >>> 24);
		r.cache[r.cacheIndex++] = (byte)(nodeId >>> 16);
		r.cache[r.cacheIndex++] = (byte)(nodeId >>> 8);
		r.cache[r.cacheIndex++] = (byte)(nodeId);
	}
}
